package com.googlecode.cpbi.util;

import java.io.IOException;
import java.net.URL;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;

import org.springframework.core.io.Resource;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

/**
 * @author Jeremy Wales
 */
public class Jar {
	private static final JarInputStream NOT_A_JAR = null;
	private final URL location;
	private final JarInputStream inputStream;

	public Jar(URL jarLocation) {
		location = jarLocation;
		inputStream = getJarInputStreamFrom(location);
	}

	public URL getLocation() {
		return location;
	}

	public boolean exists() {
		return inputStream != NOT_A_JAR;
	}

	public boolean isOsgiBundle() throws IOException {
		return StringUtils.hasText(new BundleManifest(getManifest()).getSymbolicName());
	}

	public Manifest getManifest() throws IOException {
		Manifest manifest = inputStream.getManifest();
		if (manifest == null) {
			manifest = getManifestFrom(location);
		}
		return manifest;
	}

	public JarEntry getNextEntry() throws IOException {
		return inputStream.getNextJarEntry();
	}

	public Resource getEntryNamed(String entryName) {
		return FileUtils.getResourceAt(ResourceUtils.URL_PROTOCOL_JAR + ":" + location + ResourceUtils.JAR_URL_SEPARATOR + entryName);
	}

	public void close() {
		FileUtils.close(inputStream, location);
	}

	public static boolean isJarUrl(URL url) {
		return ResourceUtils.URL_PROTOCOL_JAR.equals(url.getProtocol());
	}

	private static JarInputStream getJarInputStreamFrom(URL location) {
		try {
			return new JarInputStream(FileUtils.getInputStreamFrom(location));
		} catch (IOException e) {
			return NOT_A_JAR;
		}
	}

	private static Manifest getManifestFrom(URL jarLocation) throws IOException {
		JarFile jarFile = new JarFile(FileUtils.getFileAt(jarLocation));
		Manifest manifest = jarFile.getManifest();
		jarFile.close();
		return manifest;
	}
}
